﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LearningRecords
{
    public partial class Form1 : Form
    {
        DeviceSetting m_Setting;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            m_Setting = DeviceSetting.Load("配置文件");
            propertyGrid1.SelectedObject = m_Setting;

            int width = Convert.ToInt32(propertyGrid1.Width * 0.7);
            int height = Convert.ToInt32(propertyGrid1.Height * 0.2);
            SetPropertyGridColumnWidth(propertyGrid1, width);
            SetDescriptionHeight(propertyGrid1, height);
        }

        private void AddLog(string strLog)
        {
            if (strLog == null || strLog == "")
            {
                return;
            }
            string logFilePath = string.Format(@"D:\Data\Log\{0}\{1}.csv", DateTime.Now.ToString("yyyMM"), DateTime.Now.ToString("yyyMMdd"));
            string dirPath = Path.GetDirectoryName(logFilePath);
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            strLog = DateTime.Now.ToString("HH:mm:ss.f") + "," + strLog;
            string strError = "";

            try
            {
                File.AppendAllText(logFilePath, strLog + "\r\n", Encoding.UTF8);
            }
            catch (Exception ex)
            {
                strError = DateTime.Now.ToString("HH:mm:ss.f") + "," + ex.Message.ToString();
            }

            this.Invoke((MethodInvoker)delegate
            {
                lstShowLog.Items.Add(strLog);
                if (strError != "")
                {
                    lstShowLog.Items.Add(strError);
                }

                lstShowLog.SelectedIndex = lstShowLog.Items.Count - 1;
                lstShowLog.TopIndex = lstShowLog.Items.Count - 1;

                if (lstShowLog.Items.Count > 200)//满200行，就删除前190行
                {
                    for (int i = 0; i < 40; i++)
                    {
                        lstShowLog.Items.RemoveAt(0);
                    }
                }
            });
        }

        /// <summary>
        /// 设置propertyGrid第1列(属性名称)的列宽
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="width"></param>
        private void SetPropertyGridColumnWidth(PropertyGrid grid, int width)
        {
            try
            {
                if (grid == null)
                    return;

                FieldInfo fi = grid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
                if (fi == null)
                    return;

                Control view = fi.GetValue(grid) as Control;
                if (view == null)
                    return;

                MethodInfo mi = view.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic);
                if (mi == null)
                    return;
                mi.Invoke(view, new object[] { width });
            }
            catch (Exception ex)
            {
                AddLog("设置属性窗格名称列宽异常：" + ex.ToString());
            }
        }

        /// <summary>
        /// 设置propertyGrid说明窗格高度
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="height"></param>
        private void SetDescriptionHeight(PropertyGrid grid, int height)
        {
            try
            {
                if (grid == null)
                    return;

                foreach (Control control in grid.Controls)
                {
                    if (control.GetType().Name == "DocComment")
                    {
                        control.Invoke((MethodInvoker)delegate
                        {
                            control.Height = height;
                            FieldInfo fieldInfo = control.GetType().BaseType.GetField("userSized", BindingFlags.Instance | BindingFlags.NonPublic);
                            fieldInfo.SetValue(control, true);
                        });
                    }
                }
            }
            catch (Exception error)
            {
                AddLog("设置属性说明窗格高度异常：" + error.ToString());
            }
        }

        /// <summary>
        /// 通过反射以“类别属性”名称判别是否可见
        /// </summary>
        /// <param name="obj">属性对象</param>
        /// <param name="showCategoryContains">需显示的属性名称包含字符串</param>
        /// <param name="hideCategoryContains">需隐藏的属性名称包含字符串</param>
        public static void SetCategoryVisibility(object obj, string showCategoryContains, string hideCategoryContains)
        {
            Type typeBrow = typeof(BrowsableAttribute);
            Type typeCate = typeof(CategoryAttribute);

            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);

            for (int i = 0; i < props.Count; i++)
            {
                AttributeCollection attrs = props[i].Attributes;//获取特性集合，索引、属性名称都可以获取

                CategoryAttribute category = (CategoryAttribute)attrs[typeCate];
                if (showCategoryContains != "" && category.Category.Contains(showCategoryContains))
                {
                    FieldInfo fld = typeBrow.GetField("browsable", BindingFlags.Instance | BindingFlags.NonPublic);
                    fld.SetValue(attrs[typeBrow], true);
                }

                if (hideCategoryContains != "" && category.Category.Contains(hideCategoryContains))
                {
                    FieldInfo fld = typeBrow.GetField("browsable", BindingFlags.Instance | BindingFlags.NonPublic);
                    fld.SetValue(attrs[typeBrow], false);
                }
            }
        }

        /// <summary>
        /// 通过反射以“显示名称”判别是否可见
        /// </summary>
        /// <param name="obj">属性对象</param>
        /// <param name="showNameContains">需显示的名称包含字符串</param>
        /// <param name="hideNameContains">需隐藏的名称包含字符串</param>
        public static void SetDisplayNameyVisibility(object obj, string showNameContains, string hideNameContains)
        {
            Type typeBrow = typeof(BrowsableAttribute);
            Type typeCate = typeof(DisplayNameAttribute);

            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);

            for (int i = 0; i < props.Count; i++)
            {
                AttributeCollection attrs = props[i].Attributes;//获取特性集合，索引、属性名称都可以获取

                DisplayNameAttribute display = (DisplayNameAttribute)attrs[typeCate];
                if (showNameContains != "" && display.DisplayName.Contains(showNameContains))
                {
                    FieldInfo fld = typeBrow.GetField("browsable", BindingFlags.Instance | BindingFlags.NonPublic);
                    fld.SetValue(attrs[typeBrow], true);
                }

                if (hideNameContains != "" && display.DisplayName.Contains(hideNameContains))
                {
                    FieldInfo fld = typeBrow.GetField("browsable", BindingFlags.Instance | BindingFlags.NonPublic);
                    fld.SetValue(attrs[typeBrow], false);
                }
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_Setting != null)
            {
                m_Setting.Save();
            }
        }

        private void lstShowLog_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
    }
}